/* Copyright (C) 2007-2010 STS Soft

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

using System;
using System.IO;
using STSdb.General.Streams;

namespace STSdb.Files
{
    [Serializable]
    public class BlobStream : Stream, IComparable<BlobStream>
    {
        [NonSerialized]
        private long position = 0;
        private long length;
        
        public ulong Offset { get; private set; }
        [NonSerialized]
        public IFile File;

        public BlobStream(IFile file, ulong offset, long length)
        {
            //if (file == null)
            //    throw new ArgumentNullException("file");

            if (length < 0)
                throw new IndexOutOfRangeException("length");

            File = file;
            this.Offset = offset;
            this.length = length;
        }

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanSeek
        {
            get { return true; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override void Flush()
        {
            File.Flush();
        }

        public override long Length
        {
            get { return length; }
        }

        public override long Position
        {
            get { return position; }
            set { Seek(value, SeekOrigin.Begin); }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            if (count < 0)
                throw new ArgumentOutOfRangeException("count");

            count = (int)Math.Min(count, Length - position);
            File.Read(this.Offset + (ulong)position, buffer, offset, count);
            position += count;

            return count;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            long newPos = position;

            switch(origin)
            {
                case SeekOrigin.Begin:
                    newPos = offset;
                    break;
                case SeekOrigin.Current:
                    newPos = checked(position + offset);
                    break;
                case SeekOrigin.End:
                    newPos = Length - offset;
                    break;
            }

            if (newPos < 0 || newPos >= Length)
                throw new ArgumentOutOfRangeException("offset");

            position = newPos;

            return Position;
        }

        public override void SetLength(long value)
        {
            throw new NotSupportedException();
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            if (count < 0 || position + count > length)
                throw new ArgumentOutOfRangeException("count");

            File.Write(this.Offset + (ulong)position, buffer, offset, count);
            position += count;
        }

        #region IComparable<BlobStream> Members

        public int CompareTo(BlobStream other)
        {
            return StreamExtensions.CompareTo(this, other); 
        }

        #endregion
    }
}
